//
// Created by pengx on 2025/8/29.
//

#include <jni.h>
#include <string>
#include <android/log.h>
#include "sip_register.hpp"
#include "rtp_sender.hpp"

#define TAG "JNI-MediaPusher"
#define LGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

static JavaVM *g_jvm = nullptr;
static SipRegister *sip_register;

extern "C"
JNIEXPORT void JNICALL
Java_com_pengxh_app_gb28181_util_MediaPusher_register(JNIEnv *env, jobject thiz,
                                                      jobject config, jobject callback) {
    // 保存全局JVM引用
    env->GetJavaVM(&g_jvm);

    // 获取SipConfig类和字段
    jclass configClass = env->GetObjectClass(config);

    // 获取各个字段ID
    jfieldID localHostField = env->GetFieldID(configClass, "localHost", "Ljava/lang/String;");
    jfieldID serverHostField = env->GetFieldID(configClass, "serverHost", "Ljava/lang/String;");
    jfieldID serverPortField = env->GetFieldID(configClass, "serverPort", "I");
    jfieldID serverCodeField = env->GetFieldID(configClass, "serverCode", "Ljava/lang/String;");
    jfieldID serverDomainField = env->GetFieldID(configClass, "serverDomain", "Ljava/lang/String;");
    jfieldID deviceCodeField = env->GetFieldID(configClass, "deviceCode", "Ljava/lang/String;");
    jfieldID serialNumberField = env->GetFieldID(configClass, "serialNumber", "Ljava/lang/String;");
    jfieldID deviceNameField = env->GetFieldID(configClass, "deviceName", "Ljava/lang/String;");
    jfieldID passwordField = env->GetFieldID(configClass, "password", "Ljava/lang/String;");
    jfieldID longitudeField = env->GetFieldID(configClass, "longitude", "D");
    jfieldID latitudeField = env->GetFieldID(configClass, "latitude", "D");

    // 获取字段值
    auto localHost = (jstring) env->GetObjectField(config, localHostField);
    auto serverHost = (jstring) env->GetObjectField(config, serverHostField);
    jint serverPort = env->GetIntField(config, serverPortField);
    auto serverCode = (jstring) env->GetObjectField(config, serverCodeField);
    auto serverDomain = (jstring) env->GetObjectField(config, serverDomainField);
    auto deviceCode = (jstring) env->GetObjectField(config, deviceCodeField);
    auto serialNumber = (jstring) env->GetObjectField(config, serialNumberField);
    auto deviceName = (jstring) env->GetObjectField(config, deviceNameField);
    auto password = (jstring) env->GetObjectField(config, passwordField);
    jdouble longitude = env->GetDoubleField(config, longitudeField);
    jdouble latitude = env->GetDoubleField(config, latitudeField);

    // 转换 jstring 为 std::string
    const char *local_host_ptr = env->GetStringUTFChars(localHost, nullptr);
    const char *server_host_ptr = env->GetStringUTFChars(serverHost, nullptr);
    const char *server_code_ptr = env->GetStringUTFChars(serverCode, nullptr);
    const char *server_domain_ptr = env->GetStringUTFChars(serverDomain, nullptr);
    const char *device_code_ptr = env->GetStringUTFChars(deviceCode, nullptr);
    const char *serial_number_ptr = env->GetStringUTFChars(serialNumber, nullptr);
    const char *device_name_ptr = env->GetStringUTFChars(deviceName, nullptr);
    const char *password_ptr = env->GetStringUTFChars(password, nullptr);

    std::string local_host_str(local_host_ptr);
    std::string server_host_str(server_host_ptr);
    std::string server_code_str(server_code_ptr);
    std::string server_domain_str(server_domain_ptr);
    std::string device_code_str(device_code_ptr);
    std::string serial_number_str(serial_number_ptr);
    std::string device_name_str(device_name_ptr);
    std::string password_str(password_ptr);

    if (sip_register == nullptr) {
        sip_register = new SipRegister();
    }
    sip_register->initialize(local_host_str, server_host_str, serverPort,
                             server_code_str, server_domain_str, device_code_str,
                             serial_number_str, device_name_str, password_str, longitude, latitude);
    sip_register->setSipEventCallback(env, callback);

    // 释放 JNI 字符串资源
    env->ReleaseStringUTFChars(localHost, local_host_ptr);
    env->ReleaseStringUTFChars(serverHost, server_host_ptr);
    env->ReleaseStringUTFChars(serverCode, server_code_ptr);
    env->ReleaseStringUTFChars(serverDomain, server_domain_ptr);
    env->ReleaseStringUTFChars(deviceCode, device_code_ptr);
    env->ReleaseStringUTFChars(deviceName, device_name_ptr);
    env->ReleaseStringUTFChars(password, password_ptr);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_pengxh_app_gb28181_util_MediaPusher_unregister(JNIEnv *env, jobject thiz) {
    if (sip_register != nullptr) {
        sip_register->unregister();
        delete sip_register;
        sip_register = nullptr;
    }
}

///////////////////////////////////////////////////////////////////////////////////////

extern "C"
JNIEXPORT void JNICALL
Java_com_pengxh_app_gb28181_util_MediaPusher_notifySpsPps(JNIEnv *env, jobject thiz, jbyteArray sps,
                                                          jbyteArray pps) {
    if (!sps || !pps) return;

    jsize sps_len = env->GetArrayLength(sps);
    jsize pps_len = env->GetArrayLength(pps);

    std::vector<uint8_t> sps_vec(sps_len);
    std::vector<uint8_t> pps_vec(pps_len);

    env->GetByteArrayRegion(sps, 0, sps_len, reinterpret_cast<jbyte *>(sps_vec.data()));
    env->GetByteArrayRegion(pps, 0, pps_len, reinterpret_cast<jbyte *>(pps_vec.data()));

    RtpSender::getSender()->initSpsPps(sps_vec.data(), sps_len, pps_vec.data(), pps_len);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_pengxh_app_gb28181_util_MediaPusher_pushVideoFrame(JNIEnv *env, jobject thiz,
                                                            jbyteArray h264, jlong pts_90khz,
                                                            jboolean is_key_frame) {
    if (!h264) return;

    jsize len = env->GetArrayLength(h264);
    if (len <= 0) return;

    // 分配临时缓冲区
    std::vector<uint8_t> h264_temp(len);
    env->GetByteArrayRegion(h264, 0, len, reinterpret_cast<jbyte *>(h264_temp.data()));

    RtpSender::getSender()->pushVideoFrame(
            h264_temp.data(),
            h264_temp.size(),
            static_cast<uint64_t>(pts_90khz), // 数据类型一定要对应上，jlong在不同平台京都不一样！！！
            is_key_frame == JNI_TRUE
    );
}

extern "C"
JNIEXPORT void JNICALL
Java_com_pengxh_app_gb28181_util_MediaPusher_pushAudioFrame(JNIEnv *env, jobject thiz,
                                                            jbyteArray alaw, jlong pts_90khz) {
    if (!alaw) return;

    jsize len = env->GetArrayLength(alaw);
    if (len <= 0) return;

    // 分配临时缓冲区
    std::vector<uint8_t> alaw_temp(len);
    env->GetByteArrayRegion(alaw, 0, len, reinterpret_cast<jbyte *>(alaw_temp.data()));

    RtpSender::getSender()->pushAudioFrame(
            alaw_temp.data(),
            alaw_temp.size(),
            static_cast<uint64_t>(pts_90khz) // 数据类型一定要对应上，jlong在不同平台京都不一样！！！
    );
}